package org.raymond.iworks.gateway.filter;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.raymond.iworks.apis.common.ErrorCode;
import org.raymond.iworks.apis.exception.BaseException;
import org.raymond.iworks.commons.constants.CacheConstants;
import org.raymond.iworks.commons.constants.CommonConstants;
import org.raymond.iworks.core.constants.LockConstants;
import org.raymond.iworks.core.holder.CacheHolder;
import org.raymond.iworks.core.utils.RedisUtil;
import org.raymond.iworks.gateway.filter.support.GatewayContext;
import org.raymond.iworks.gateway.utils.ReactiveWebUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;
import java.util.Set;

/**
 * @author raymond
 * @version V1.0
 * @Description: TODO
 */
@Slf4j
@Component
public class RepeatSubmitFilter implements GatewayFilter, Ordered {
    @Autowired
    private CacheHolder cacheHolder;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        GatewayContext gatewayContext = exchange.getAttribute(GatewayContext.CACHE_GATEWAY_CONTEXT);
        if (gatewayContext == null) {
            throw new BaseException(ErrorCode.ERROR, "Gateway context should not be null");
        }

        String method = request.getMethod().name();
        if(!HttpMethod.POST.matches(method)){
            return chain.filter(exchange);
        }

        Set<Object> blackListIps = cacheHolder.sGet(CacheConstants.BLACK_LIST_IP);
        String remoteAddress = ReactiveWebUtil.getRemoteAddress(exchange);
        if(StringUtils.isNotBlank(remoteAddress) && CollectionUtils.isNotEmpty(blackListIps)){
            if(blackListIps.contains(remoteAddress)){
                throw new BaseException(ErrorCode.ERROR, "Can not access");
            }
        }

        String clientRequestTime = request.getHeaders().getFirst(CommonConstants.CLIENT_REQUEST_TIME);
        Date requestTime = gatewayContext.getRequestToServer();
        if(StringUtils.isNotBlank(clientRequestTime)){
            requestTime = DateUtil.parse(clientRequestTime);
        }
        String sign = gatewayContext.getSign();
        // 设置重复请求时间间隔
        long expire = RedisUtil.expire(LockConstants.LOCK_EXPIRE_REPEAT);
        boolean result = cacheHolder.set(LockConstants.LOCK_PREFIX_REPEAT + sign,
                requestTime, expire);
        log.debug("request repeat: {}-{}", result, sign);
        if(!result) {
            throw new BaseException(ErrorCode.ERROR, "Request repeat");
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
